import {getDeviceIconByType, getDeviceIconByKey} from './drawIcon'
import {message} from 'ant-design-vue';


export class Board {
    constructor(stage, layer, stageMenu, deviceRemarkBox) {
        this.stage = stage;
        this.layer = layer;
        this.stageMenu = stageMenu;
        this.deviceRemarkBox = deviceRemarkBox;

        this.scale_rate = 1.0;
        this.strokeHistory = [];
        this.strokeRemoved = [];
        this.isPaint = false;
        this.selectedShapeId = null
        this.contextmenuShapeId = null
        this.contextmenuAction = null

        this.eanbleScaleDown = true;
        this.eanbleScaleUp = true;
        // this.boardConfig = config;
        this.boardConfig = {
            fontSize: 16,
            strokeWidth: 1,
            strokeColor: '#000000',
        }
        this.$message = message;
    }

    undoStroke() {
        let shape = this.strokeHistory.pop()
        if (!shape) return
        this.strokeRemoved.push(shape)
        shape.remove()
        this.layer.draw()
    }

    redoStroke() {
        let shape = this.strokeRemoved.pop()
        if (!shape) return
        this.strokeHistory.push(shape)
        this.layer.add(shape)
        this.layer.draw()
    }

    _recoverLayerAttr(draw_json){
        console.log(draw_json.attrs._stageWidth)
        if(draw_json.attrs._stageWidth) {

            this.layer.setAttrs({
                _stageWidth: draw_json.attrs._stageWidth,
                _stageHeight: draw_json.attrs._stageHeight
            })
        }
    }

    recoverDraw(p_data, bindEvent, iterFunc) {
        this.layer.destroyChildren()
        let draw_json = JSON.parse(p_data.drawingInfo)
        this._recoverLayerAttr(draw_json)

        for (const sharp of draw_json.children) {
            let _konvaSharp = Konva.Node.create(sharp);
            this.layer.add(_konvaSharp)
            if(sharp.attrs.id === 'globalGg') {
                this.addBg(p_data.reproduction, false)
                // let bg = this.layer.findOne('#globalGg');
                // const img = new Image()
                // img.src = p_data.reproduction;
                // bg.setAttrs({ image: img })
                this.layer.draw()
            }
            else {
                if(bindEvent) {
                    this.bindShapeEvent(_konvaSharp);
                }
            }
            iterFunc(sharp);

            if (sharp.attrs._meta && sharp.attrs._meta.type === 'device') {

                for (const c of sharp.children) {
                    if (c.attrs._meta && c.attrs._meta.icon) {
                        // 加载测点icon
                        let img = new Image()
                        img.src = getDeviceIconByKey(c.attrs._meta.icon)
                        let drawing_img = this.layer.findOne('#' + c.attrs.id)
                        drawing_img.setAttrs({
                            image: img
                        })
                        this.layer.batchDraw()
                    }
                }
            }
            this.layer.batchDraw()
        }
    }

    recoverDrawForMobile(p_data, clientWidth, clientHeight, iterFunc) {
        // 手机端还原测点图
        this.layer.destroyChildren()
        let draw_json = JSON.parse(p_data.drawingInfo)
        this._recoverLayerAttr(draw_json)

        this.stage.setAttrs({
            draggable: true,
        })
        // this.stage.scale({
        //     x: 0.5,
        //     y: 0.5
        // })
        let has_bg = false;
        for (const sharp of draw_json.children) {
            let _sharpNode = Konva.Node.create(sharp);
            this.layer.add(_sharpNode)
            if(sharp.attrs.id === 'globalGg') {
                has_bg = true;
                let bg = this.layer.findOne('#globalGg')
                const img = new Image()
                img.src = p_data.reproduction;
                bg.setAttrs({ image: img })
                img.onload = () => {
                    let _stageWidth = img.width;
                    let _stageHeight = img.height
                    this.layer.setAttrs({
                        _stageWidth: _stageWidth,
                        _stageHeight: _stageHeight
                    })
                    this.setUpBg(clientWidth, clientHeight)
                }

            }
            else {
                _sharpNode.setAttrs({draggable: false})
            }
            iterFunc(sharp);

            if (sharp.attrs._meta && sharp.attrs._meta.type === 'device') {
                // this.syncDeviceShowStatus(sharp.attrs._meta.device_id)
                for (const c of sharp.children) {
                    if (c.attrs._meta && c.attrs._meta.icon) {
                        // 加载测点icon
                        let img = new Image()
                        img.src = getDeviceIconByKey(c.attrs._meta.icon)
                        let drawing_img = this.layer.findOne('#' + c.attrs.id)
                        drawing_img.setAttrs({
                            image: img
                        })
                        // this.layer.batchDraw()
                    }
                }
            }
        }
        if(!has_bg) {
            this.setUpBg(clientWidth, clientHeight)
        }
        this.layer.batchDraw()
    }

    setUpBg(clientWidth, clientHeight) {
        this.stage.width(clientWidth);
        this.stage.height(clientHeight);
        this.stage.draw();
        let bg = this.layer.findOne('#globalGg')
        let stage_width = this.layer.attrs._stageWidth;
        let stage_height = this.layer.attrs._stageHeight;
        console.log('stage size from layer:', stage_width, stage_height)

        if(!stage_width && bg) {
            stage_width = bg.attrs.image.width
            stage_height = bg.attrs.image.height
            // console.log(bg.image())
            console.log('stage size from bg:', stage_width, stage_height)
            console.log('bg.size', bg.size())
        }
        if(!bg){
            this.stage.getContainer().style.backgroundColor = '#f5f5f5';
        }
        // min_x_offset = min_x_offset < clientWidth
        // console.log('min_x', min_x_offset)

        this.stage.setAttrs({
            dragBoundFunc: (pos) => {
                let min_x_offset = -1 * stage_width * this.stage.scaleX() + clientWidth
                let min_y_offset = -1 * stage_height * this.stage.scaleY() + clientHeight

                let res = {
                    x: pos.x,
                    y: pos.y
                };
                if(res.x > 0) {
                    res.x = 0;
                }
                if(res.y > 0) {
                    res.y = 0;
                }

                if(res.x < min_x_offset) {
                    res.x = min_x_offset
                }
                if(res.y < min_y_offset) {
                    res.y = min_y_offset
                }
                // console.log('min_x', min_x_offset)
                // console.log('pos', pos)
                return res;
            },
        })
    }

    addDevice(device) {
        let exists_device = this.layer.findOne('#deviceGroup-' + device.id)
        if (!exists_device) {
            this.drawDevice(device, 20, 20)
        }
    }
    toggleShowDevice(device) {
        let exists_device = this.layer.findOne('#deviceGroup-' + device.id);
        if (!exists_device) return;
        device.show = !device.show;
        if (device.show) {
            exists_device.show()
        } else {
            exists_device.hide()
        }
        this.layer.draw()
    }

    dragBound(pos) {
        let res = {
            x: pos.x,
            y: pos.y
        }

        if (res.x <= 0) res.x = 0;
        if (res.y <= 0) res.y = 0;
        let max_width = this.stage.width() - 40
        let max_height = this.stage.height() - 40

        if (res.x > max_width) {
            res.x = max_width
        }
        if (res.y > max_height) {
            res.y = max_height
        }

        return res;
    }

    updateTextShape(newText) {
        if (!newText || !newText.trim()) return

        let txt = new Konva.Text({
            id: this.genID(),
            x: 15,
            y: 15,
            text: newText,
            fontSize: this.boardConfig.fontSize,
            // fontFamily: 'Calibri',
            fill: this.boardConfig.strokeColor,
            draggable: true,
            dragBoundFunc: (pos) => {
                return this.dragBound(pos);
            },
            _meta: {
                title: '文字'
            }
        })
        this.bindShapeEvent(txt)
        this.layer.add(txt)
        this.layer.draw()
    }

    drawDevice(device, x, y) {

        device.draw = true;
        device.show = true;
        let device_group = new Konva.Group({
            id: 'deviceGroup-' + device.id,
            x: x,
            y: y,
            // width: 30,
            // height: 18,
            zIndex: 100,
            draggable: true,
            dragBoundFunc: (pos) => {
                return this.dragBound(pos)
            },
            _meta: {
                'title': device.name,
                'type': 'device',
                'type_id': device.type,
                'device_id': device.id,
                'remark': '',
                'line_ids': [],
            }
        })
        this.bindShapeEvent(device_group)

        let device_icon = this.getDeviceIcon(device.type)
        let img_width = 18
        Konva.Image.fromURL(device_icon.data, (img) => {
            console.log(img)
            img.setAttrs({
                id: 'deviceIcon-' + device.id,
                x: device_group.attrs.x,
                y: device_group.attrs.y,
                zIndex: 100,
                width: img_width,
                height: img_width,
                _meta: {
                    icon: device_icon.key
                }
            })
            // this.layer.add(img);
            device_group.add(img)
            this.layer.batchDraw()
        })

        let font_size = 12
        let text = new Konva.Text({
            id: 'deviceText-' + device.id,
            x: device_group.attrs.x + img_width,
            y: device_group.attrs.y + (img_width - font_size) / 2,
            zIndex: 100,
            fontSize: font_size,
            text: device_group.attrs._meta.title,
            fill: '#000000',
            shadowColor: 'white',
            shadowBlur: 15,
            shadowOffsetX: 2,
            shadowOffsetY: 2,
            shadowOpacity: 0.2,
        })
        device_group.add(text)

        this.layer.add(device_group)
        this.layer.draw()
    }
    setDeviceTextColor(device_id, hexStr, display_warning) {
        let textNode = this.layer.findOne('#deviceText-' + device_id);

        let deviceIcon = this.layer.findOne('#deviceIcon-' + device_id);
        console.log('deviceNode', deviceIcon)
        if(deviceIcon && display_warning) {
            let deviceGroup = this.layer.findOne('#deviceGroup-' + device_id);
            let period = 2500;

            // console.log()
            let circle = new Konva.Circle({
                x: deviceIcon.getAbsolutePosition().x - 8,
                y: deviceIcon.getAbsolutePosition().y + 8,
                radius: 6,
                fill: '#ff0000',
                stroke: '#ffffff',
                strokeWidth: 1
            });
            circle.shadowOpacity(1);
            circle.shadowColor('#ff0000');

            this.layer.add(circle);
            let anim = new Konva.Animation(function (frame) {
                let scale = Math.sin((frame.time * 2 * Math.PI) / period) + 0.001;
                // scale x and y
                // console.log('scale', scale);

                // circle.radius(5 * Math.abs(scale) + 1 )
                circle.opacity(Math.abs(scale));
                // circle.shadowBlur(12*Math.abs(scale));
                // deviceIcon.shadowOffset({ x: 20, y: 20 });

            }, this.layer);

            anim.start();
        }

        if(textNode){
            textNode.fontStyle('500');
            if(display_warning){
                textNode.fill('#ff0000')
            }
            else {
                textNode.fill('#000000')
            }


            this.layer.batchDraw();
        }
    }

    startRotate() {
        if (!this.selectedShapeId) {
            this.$message.info('请选择测点或绘图元素')
            return
        }
        let shape = this.layer.findOne('#' + this.selectedShapeId)
        let exists_tr = this.layer.findOne('#' + this.selectedShapeId + '-transformer')
        if (exists_tr) {
            exists_tr.destroy()
            this.layer.draw()
            return
        }

        if (shape) {
            var tr = new Konva.Transformer({
                id: shape.attrs.id + '-transformer',
                centeredScaling: true,
                rotationSnaps: [0, 90, 180, 270],
                resizeEnabled: false
            })
            this.layer.add(tr)
            tr.nodes([shape])
            this.layer.draw()
        }
    }

    connectDevice(device_from, device_to) {
        let _this = this;
        let from_id = device_from.attrs._meta.device_id;
        let to_id = device_to.attrs._meta.device_id;
        if (from_id === to_id) return;
        let line_id = `connector-${Math.min(from_id, to_id)}-${Math.max(from_id, to_id)}`;
        let exists_line = this.layer.findOne('#' + line_id);

        let _icon_from = this.layer.findOne('#deviceIcon-' + from_id);
        let _from = {
            x: device_from.x() + _icon_from.x() + _icon_from.width()/2,
            y: device_from.y() + _icon_from.y() + _icon_from.height()/2
        }

        let _icon_to = this.layer.findOne('#deviceIcon-' + from_id);
        // let to = {
        //     x: device_to.x() + 24,
        //     y: device_to.y() + 28
        // }
        let to = {
            x: device_to.x() + _icon_to.x() + _icon_to.width()/2,
            y: device_to.y() + _icon_to.y() + _icon_to.height()/2,
        }
        const dx = to.x - _from.x;
        const dy = to.y - _from.y;
        let angle = Math.atan2(-dy, dx);
        const radius = 5;

        let points = [
            _from.x + -radius * Math.cos(angle + Math.PI),
            _from.y + radius * Math.sin(angle + Math.PI),
            to.x + -radius * Math.cos(angle),
            to.y + radius * Math.sin(angle),
        ];

        if (exists_line) {
            // 已经存在直接更新点坐标
            exists_line.points(points)
            this.layer.batchDraw()
            return;
        }

        let lineConfig = {
            id: line_id,
            points: points,
            zIndex: 1,
            stroke: this.boardConfig.strokeColor,
            strokeWidth: this.boardConfig.strokeWidth,
            lineJoin: 'round',
            opacity: 0.8,
            _meta: {
                title: '直线',
                from_id: device_from.attrs.id,
                to_id: device_to.attrs.id,
            }
        }
        device_from.attrs._meta.line_ids.push(line_id)
        device_to.attrs._meta.line_ids.push(line_id)

        let line = new Konva.Line(lineConfig)
        this.layer.add(line)
        _this.contextmenuShapeId = null;
        this.layer.draw()
    }
    startConnectDevice() {
        if (!this.contextmenuShapeId) {
            this.$message.info('请先选择测点')
            return;
        }
        this.contextmenuAction = 'connect'
        this.hideMenu()
        this.$message.info('请鼠标左键点击另一个测点')
    }

    showDevice(deviceNode, show) {
        if(deviceNode) {
            // console.log(t.show)
            show ? deviceNode.show() : deviceNode.hide();
            console.log(deviceNode.attrs._meta.line_ids)
            if(deviceNode.attrs._meta.line_ids && deviceNode.attrs._meta.line_ids.length > 0) {
                for(let l_id of deviceNode.attrs._meta.line_ids) {
                    let _line = this.layer.findOne('#' + l_id);
                    console.log(_line)
                    if(_line) {
                        show ? _line.show() : _line.hide()
                    }
                }
            }
        }
    }

    startRemarkDevice() {
        if (!this.contextmenuShapeId) {
            this.$message.info('请先选择测点')
            return;
        }
        this.contextmenuAction = 'remark'
        let shape = this.layer.findOne('#' + this.contextmenuShapeId)
        if (!shape) return;

        this.deviceRemarkBox.style.display = 'initial'
        this.deviceRemarkBox.style.top = shape.y() - 90 + 'px';
        this.deviceRemarkBox.style.left = shape.x() + 16 + 'px';

        this.hideMenu()
    }
    saveDeviceRemark(content) {

        let shape = this.layer.findOne('#' + this.contextmenuShapeId)
        if (!shape) return;
        shape.attrs._meta.remark = content

        this.deviceRemarkBox.style.display = 'none'
    }

    cancelDeviceRemark() {
        this.deviceRemarkBox.style.display = 'none'
    }

    bindShapeEvent(shape) {
        // 绑定元素选中事件
        let _this = this
        let is_device = shape.attrs._meta && shape.attrs._meta.type === 'device';

        console.log('bindEvent')
        shape.on('click', (e) => {
            console.log(111)
            if (_this.isPaint) {
                return;
            }
            if (e.evt.button !== 0) {
                // 非鼠标左键点击
                return;
            }

            if (_this.contextmenuShapeId !== null && _this.contextmenuAction === 'connect' && is_device) {
                // 测点连线
                let from_device = this.layer.findOne('#' + _this.contextmenuShapeId);
                _this.connectDevice(from_device, shape)
                return;
            }
            console.log(111)
            _this.selectedShapeId = shape.attrs.id
            if (shape.attrs._meta && shape.attrs._meta.title) {
                _this.$message.info('已选中' + shape.attrs._meta.title)
            } else {
                _this.$message.info('已选中元素')
            }
        })

        shape.on('mouseenter',  () => {
            if (!_this.isPaint) {
                this.stage.container().style.cursor = 'pointer'
            }
        })

        shape.on('mouseleave',  () => {
            if (_this.isPaint) {
                this.stage.container().style.cursor = 'crosshair'
            } else {
                this.stage.container().style.cursor = 'default'
            }
        })

        // 设备右键菜单
        if (is_device) {
            let menuNode = this.stageMenu
            shape.on('contextmenu', (e) => {
                // prevent default behavior
                e.evt.preventDefault();
                _this.contextmenuShapeId = shape.attrs.id;

                // show menu
                menuNode.style.display = 'initial';
                // let containerRect = stage.container().getBoundingClientRect();
                menuNode.style.top = this.stage.getPointerPosition().y + 10 + 'px';
                menuNode.style.left = this.stage.getPointerPosition().x + 16 + 'px';
            });

            shape.on('dragmove', () => {
                if (shape.attrs._meta && shape.attrs._meta.line_ids.length > 0) {
                    for (let line_id of shape.attrs._meta.line_ids) {
                        let l = this.layer.findOne('#' + line_id)
                        if (!l) continue;
                        let from_id = l.attrs._meta.from_id;
                        let to_id = l.attrs._meta.to_id;
                        let from_device = this.layer.findOne('#' + from_id)
                        let to_device = this.layer.findOne('#' + to_id);
                        if (from_device && to_device) {
                            this.connectDevice(from_device, to_device)
                        }
                    }
                }
            });
        }
    }

    addBg(src, destroy) {
        let bg = this.layer.findOne('#globalGg')
        if (destroy && bg) {
            bg.destroy()
        }
        if(!bg) {
            Konva.Image.fromURL(src, (img) => {
                img.setAttrs({
                    id: 'globalGg',
                    x: 0,
                    y: 0
                    // width: img.width,
                    // height: img.height,
                })
                img.zIndex(0)
                this.stage.setAttrs({
                    width: img.attrs.image.width,
                    height: img.attrs.image.height
                })
                this.layer.setAttrs({
                    _stageWidth: img.attrs.image.width,
                    _stageHeight: img.attrs.image.height
                })
                this.layer.add(img)
                this.layer.draw()
            })
        }
        else {
            const img = new Image()
            img.src = src;
            bg.setAttrs({ image: img })

            this.layer.batchDraw()
            setTimeout(() => {
                this.stage.setAttrs({
                    width: bg.attrs.image.width,
                    height: bg.attrs.image.height
                })
            }, 1)
        }
    }

    removeBg() {
        // 删除底图
        let bg = this.layer.findOne('#globalGg')
        if (bg) {
            bg.destroy()
            this.stage.width(800);
            this.stage.height(800);
            this.layer.setAttrs({
                _stageWidth: img.attrs.image.width,
                _stageHeight: img.attrs.image.height
            })
            this.layer.batchDraw()
        }
    }

    hideMenu() {
        let menuNode = this.stageMenu;
        menuNode.style.display = 'none';
    }
    cancelMenu() {
        this.contextmenuShapeId = null;
        this.hideMenu()
    }

    deleteSelectedShape() {
        if (!this.selectedShapeId) {
            this.$message.error('请选择绘图元素或测点')
            return
        }

        let shape = this.layer.findOne('#' + this.selectedShapeId)
        if (shape) {
            let is_device = shape.attrs._meta && shape.attrs._meta.type === 'device';
            if (is_device) {
                if (shape.attrs._meta.line_ids.length > 0) {
                    for (let line_id of shape.attrs._meta.line_ids) {
                        let _line = this.layer.findOne('#' + line_id);
                        if (_line) {
                            _line.destroy()
                        }
                    }
                }
                // let device = this.devices.find(i => i.id == shape.attrs._meta.device_id);
                // if (device) {
                //     device.draw = false;
                //     device.show = false;
                // }
            }
            shape.destroy()
            this.layer.batchDraw()
        }
        let exists_tr = this.layer.findOne('#' + this.selectedShapeId + '-transformer')
        if (exists_tr) {
            exists_tr.destroy()
            this.layer.draw()
        }
    }

    startDrawLine(lineStyle) {
        // 绘制直线和虚线
        let _this = this;

        let _lastLine = null;
        let _lastPoint = null;
        this.stage.on('mousedown',  (e) => {

            if (e.evt.button != 0) {
                // 非鼠标左键点击
                return;
            }

            _this.isPaint = true
            let mousePos = this.stage.getPointerPosition()
            _lastPoint = {
                x: mousePos.x / this.stage.scaleX(),
                y: mousePos.y / this.stage.scaleX(),
            }
            if (_lastLine) {
                _this.strokeHistory.push(_lastLine)

                _lastLine = null;
            }
        })
        this.stage.container().style.cursor = 'crosshair'

        // 右键取消
        this.stage.on('contextmenu', (e) => {
            e.evt.preventDefault();
            // if (e.target === stage) {
            //   return;
            // }
            console.log(_lastLine)
            _this.isPaint = false

            if (_lastLine) {
                _lastLine.destroy()
                this.layer.batchDraw()
                _lastLine = null;
            }
            _lastPoint = null;

            _this.$message.info('绘图已结束')
            this.stage.container().style.cursor = 'default';
            this.stage.off('mousedown')
            this.stage.off('mousemove')
            this.stage.off('mouseup')
            this.stage.off('contextmenu')
        });


        this.stage.on('mousemove', () => {
            if (!_this.isPaint) {
                return
            }

            const pos = this.stage.getPointerPosition()
            if (_lastLine) {
                // _lastLine.destroy()
                _lastLine.points([_lastPoint.x, _lastPoint.y, pos.x / this.stage.scaleX(), pos.y / this.stage.scaleX()])
            } else {
                _lastLine = _this.drawLine(_lastPoint.x, _lastPoint.y, pos.x / this.stage.scaleX(), pos.y / this.stage.scaleX(), lineStyle)
                this.layer.add(_lastLine)
            }

            this.layer.batchDraw()
        })
    }

    drawLine(x, y, end_x, end_y, lineStyle) {
        let lineConfig = {
            id: this.genID(),
            points: [x, y, end_x, end_y],
            stroke: this.boardConfig.strokeColor,
            strokeWidth: this.boardConfig.strokeWidth,
            // globalCompositeOperation: 'copy',
            lineJoin: 'round',
            _meta: {
                title: lineStyle === 'dash' ? '虚线' : '直线',
            }
        }
        if (lineStyle === 'dash') {
            lineConfig.dash = [3, 2]
        }
        return new Konva.Line(lineConfig)
    }

    getDeviceIcon(device_type) {
        let key = `t_id_${device_type}`
        console.log(key)
        return {key: key, data: getDeviceIconByType(device_type)}
    }

    scaleUp() {
        let old_scale = this.stage.scaleX()
        let x = old_scale + 0.25
        this.stage.scale({
            x: x,
            y: x,
        })
        let stage_width = this.stage.width() * x / old_scale;
        let stage_height = this.stage.height() * x / old_scale;
        this.stage.setAttrs({
            width: stage_width,
            height: stage_height,
        })
        this.layer.draw()
        this.$message.info(`当前缩放比例${x}, 宽度${stage_width}`)
    }

    scaleDown() {

        let old_scale = this.stage.scaleX()
        let x = old_scale - 0.25
        if (x <= 0) {
            this.$message.info('已到最低缩放比例')
            return
        }
        this.stage.scale({
            x: x,
            y: x
        })

        let stage_width = this.stage.width() * x / old_scale;
        let stage_height = this.stage.height() * x / old_scale;
        this.stage.setAttrs({
            width: stage_width,
            height: stage_height,
        })
        this.layer.draw()
        this.$message.info(`当前缩放比例${x}, 宽度${stage_width}`)
    }

    scaleMobile(rate) {
        // 移动端缩放不改不stage大小
        this.stage.scale({
            x: rate,
            y: rate,
        })
        this.layer.draw()
    }

    updateConfig(config) {
        Object.assign(this.boardConfig, config)
    }

    genID() {
        // 生成id
        let randomLength = 12
        let idStr = Date.now().toString(36)
        idStr += Math.random().toString(36).substr(3, randomLength)
        return idStr
    }
}
